﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RouterControl.Db;
using UPNP.IO;

internal static class DeviceDomDbExtensionMethods
{/* TODO: implement device dom loading support
	public static DeviceDom ToDeviceDom(this DeviceDomDb db)
	{
		// handle root element
		var dom = new DeviceDom();

		dom.SchemaId = db.SchemaId;

		dom.RootDevice = db.RootDevice.ToDeviceDom();

		// finalize
		return dom;
	}

	private static DeviceDom.Device ToDeviceDom(this DeviceDb db)
	{
		// the device
		var dev = new DeviceDom.Device();

		dev.DeviceName = db.DeviceName;
		dev.DeviceTypeId = db.DeviceTypeId;
		dev.IsOptional = db.IsOptional;
		dev.IsRootDevice = db.IsRootDevice;
		
		// services
		foreach (var s in db.Services)
		{
			dev.Services.Add(s.ToDeviceDom());
		}

		// child devices
		foreach (var c in db.ChildDevices)
		{
			dev.ChildDevices.Add(c.ToDeviceDom());
		}

		// finalize
		return dev;
	}

	private static DeviceDom.Service ToDeviceDom(this ServiceDb db)
	{
		// the service
		var serv = new DeviceDom.Service();

		serv.ServiceName = db.ServiceName;
		serv.ServiceTypeId = db.ServiceTypeId;
		
		// add the state variables
		foreach (var sv in db.StateVariables)
		{
			var t = new DeviceDom.StateVariable();

			t.VariableName = sv.VariableName;
			t.DataTypeName = sv.DataTypeName;
			t.IsOptional = sv.IsOptional;
			t.SendEventsAttribute = sv.SendEventsAttribute;

			t.AllowedValues = (from av in sv.AllowedValues
							  select av.Value).ToArray();

			serv.StateVariables.Add(t);
		}

		// add the actions
		foreach (var act in db.Actions)
		{
			var a = new DeviceDom.Action();

			a.ActionName = act.ActionName;

			// arguments
			var arguments = from arg in act.Arguments
							orderby arg.ArgumentOrder
							select arg;

			foreach (var arg in arguments)
			{
				var aa = new DeviceDom.ActionArgument();

				aa.ArgumentName = arg.ArgumentName;
				aa.Direction = (arg.DirectionIsOut ? DeviceDom.ActionParameterDirection.Out : DeviceDom.ActionParameterDirection.In);
				aa.RelatedVariable = serv.GetStateVariableByName(arg.RelatedStateVariable.VariableName);

				a.Arguments.Add(aa);
			}

			serv.Actions.Add(a);
		}

		// finalize
		return serv;
	}*/

	public static DeviceDomDb Clone(this DeviceDomDb src)
	{
		var ret = new DeviceDomDb()
		{
			DomType = src.DomType,
			MaxSpecParsed = src.MaxSpecParsed,
			SchemaId = src.SchemaId,
			Version = src.Version,
			RootDevice = src.RootDevice.Clone()
		};

		// copy xml
		if (src.SchemaXml != null)
		{
			ret.SchemaXml = new System.Xml.Linq.XDocument();

			using (var xw = ret.SchemaXml.CreateWriter())
			{
				src.SchemaXml.Save(xw);
			}
		}

		return ret;
	}

	public static DeviceDb Clone(this DeviceDb src)
	{
		var ret = new DeviceDb()
		{
			DeviceName = src.DeviceName,
			DeviceTypeId = src.DeviceTypeId,
			IsOptional = src.IsOptional,
			IsRootDevice = src.IsRootDevice
		};

		// clone services
		foreach (var s in src.Services)
		{
			ret.Services.Add(s.Clone());
		}

		// clone children
		foreach (var c in src.ChildDevices)
		{
			ret.ChildDevices.Add(c.Clone());
		}

		return ret;
	}

	public static ServiceDb Clone(this ServiceDb src)
	{
		var ret = new ServiceDb()
		{
			ServiceName = src.ServiceName,
			ServiceTypeId = src.ServiceTypeId
		};

		// clone state variables
		foreach (var sv in src.StateVariables)
		{
			ret.StateVariables.Add(sv.Clone());
		}

		// clone actions
		foreach (var a in src.Actions)
		{
			ret.Actions.Add(a.Clone(ret));
		}

		return ret;
	}

	public static StateVariableDb Clone(this StateVariableDb src)
	{
		var ret = new StateVariableDb()
		{
			DataTypeName = src.DataTypeName,
			IsOptional = src.IsOptional,
			SendEventsAttribute = src.SendEventsAttribute,
			VariableName = src.VariableName
		};

		// copy allowed values
		foreach (var av in src.AllowedValues)
		{
			ret.AllowedValues.Add(
				new AllowedValueDb()
				{
					Value = av.Value
				});
		}

		return ret;
	}

	public static ActionDb Clone(this ActionDb src, ServiceDb parentService)
	{
		if (parentService == null)
			throw new ArgumentNullException("parentService");

		// continue
		var ret = new ActionDb()
		{
			ActionName = src.ActionName
		};

		// clone arguments
		foreach (var arg in src.Arguments)
		{
			ret.Arguments.Add(
				new ActionArgumentDb()
				{
					ArgumentName = arg.ArgumentName,
					ArgumentOrder = arg.ArgumentOrder,
					DirectionIsOut = arg.DirectionIsOut,
					RelatedStateVariable = (
						from psv in parentService.StateVariables
						where psv.VariableName == arg.RelatedStateVariable.VariableName
						select psv
						).Take(1).First()
				});
		}

		return ret;
	}

}
